Ohjelmointikielikirjoissa selitetään, että pinoon luodaan arvotyypit ja kasaan luodaan viitetyypit selittämättä, mitä nämä kaksi asiaa ovat. En ole lukenut selkeää selitystä tälle. Ymmärrän mitä pino on. Mutta, Missä ja mitä ne ovat (fyysisesti todellisen tietokoneen muistissa)? Missä määrin niitä ohjaa käyttöjärjestelmä tai kielen ajoaika? Mikä on niiden soveltamisala? Mikä määrittää kunkin koon? Mikä tekee siitä nopeamman?
2020-12-07 21:40:27
Pino on muisti, joka on varattu raaputuspaikaksi suorituslangalle. Kun toimintoa kutsutaan, lohko varataan pinon yläosaan paikallisille muuttujille ja joillekin kirjanpitotiedoille. Kun toiminto palaa, lohko muuttuu käyttämättömäksi ja sitä voidaan käyttää seuraavan kerran, kun toiminto kutsutaan. Pino on aina varattu LIFO-järjestyksessä (viimeinen ensin ulos); viimeksi varattu lohko on aina seuraava vapautettava lohko. Tämän ansiosta pinon seuranta on todella helppoa; lohkon vapauttaminen pinosta ei ole muuta kuin yhden osoittimen säätäminen. Kasa on muisti, joka on varattu dynaamiseen allokointiin. Toisin kuin pino, lohkojen allokoinnissa ja jakamisessa kasasta ei ole pakotettua mallia; voit jakaa lohkon milloin tahansa ja vapauttaa sen milloin tahansa. Tämä tekee paljon monimutkaisemmaksi seurata, mitkä kasan osat on varattu tai vapaa milloin tahansa; on olemassa monia mukautettuja kasanallokaattoreita, jotka voivat säätää kasan suorituskykyä eri käyttötavoille. Jokainen säie saa pinon, kun taas sovellukselle on tyypillisesti vain yksi kasa (vaikka ei ole harvinaista, että useita kasoja erityyppisille allokoinnille). Voit vastata kysymyksiisi suoraan: Missä määrin niitä ohjaa käyttöjärjestelmä tai kielen ajonaika? Käyttöjärjestelmä allokoi pinon jokaiselle järjestelmätason ketjulle, kun ketju luodaan. Tyypillisesti kielen ajonaikainen käyttöjärjestelmä kutsuu kasan varaamista sovellukselle. Mikä on niiden soveltamisala? Pino on kiinnitetty langalle, joten kun lanka poistuu, pino otetaan takaisin. Kasa allokoidaan tyypillisesti sovelluksen käynnistyksen yhteydessä ajonaikaisesti, ja se otetaan takaisin, kun sovellus (teknisesti prosessi) poistuu. Mikä määrittää kunkin koon? Pino koko määritetään, kun ketju luodaan. Kasan koko määritetään sovelluksen käynnistyksen yhteydessä, mutta se voi kasvaa, kun tilaa tarvitaan (allokaattori pyytää lisää muistia käyttöjärjestelmästä). Mikä tekee siitä nopeamman? Pino on nopeampi, koska pääsykuvion vuoksi on triviaalia jakaa ja jakaa muistia siitä (osoitinta / kokonaislukua yksinkertaisesti kasvatetaan tai vähennetään), kun taas kasalla on paljon monimutkaisempi kirjanpito, joka liittyy allokointiin tai jakautumiseen. Lisäksi jokaista pinon tavua käytetään yleensä erittäin usein uudelleen, mikä tarkoittaa, että se yleensä kartoitetaan prosessorin välimuistiin, mikä tekee siitä erittäin nopean. Toinen kasan suorituskyky on se, että kasan, joka on enimmäkseen globaali resurssi, on yleensä oltava monisäikeinen, ts. Jokainen allokointi ja jakautuminen on - tyypillisesti - synkronoitava "kaikkien" muiden ohjelman kasaan pääsyjen kanssa. Selkeä mielenosoitus: Kuvalähde: vikashazrati.wordpress.com | Pino: Tallennetaan tietokoneen RAM-muistiin aivan kuin kasa. Pinoan luodut muuttujat poistuvat soveltamisalasta ja jaetaan automaattisesti. Paljon nopeampi allokoida kuin kasan muuttujat. Toteutettu varsinaisella pinon tietorakenteella. Tallentaa parametrien välittämiseen käytetyt paikalliset tiedot, palautusosoitteet. Voi olla pinon ylivuoto, kun pinosta käytetään liikaa (enimmäkseen ääretön tai liian syvä rekursio, erittäin suuret allokaatiot). Pinoon luotuja tietoja voidaan käyttää ilman viitteitä. Käytä pinoa, jos tiedät tarkalleen kuinka paljon tietoa sinun on jaettava ennen kääntöaikaa, eikä se ole liian iso. Tavallisesti enimmäiskoko on jo määritetty ohjelman käynnistämisen yhteydessä. Pino: Tallennetaan tietokoneen RAM-muistiin aivan kuin pino. C ++: ssa kasan muuttujat on tuhottava manuaalisesti, eivätkä ne koskaan saa jäädä soveltamisalan ulkopuolelle. Tiedot vapautetaan poistamalla, poistamalla [] tai ilmaiseksi. Hitaampi allokoida verrattuna pinon muuttujiin. Käytetään pyynnöstä tietolohkon allokoimiseksi ohjelman käyttöä varten. Voi olla pirstoutunutta, kun allokaatioita ja jakaumia on paljon. C ++: ssa tai C: ssä kasaan luodut tiedot osoittavat osoittimet ja allokoidaan uudella tai mallocilla. Voi olla allokointivirheitä, jos liian suurta puskuria pyydetään varaamaan. Käytä kasaa, jos et tiedä tarkalleen kuinka paljon tietoa tarvitset ajon aikana tai jos sinun on allokoitava paljon dataa. Vastuussa muistivuodoista. Esimerkki: int foo () { char * pBuffer; // <- mitään ei ole vielä varattu (lukuun ottamatta itse osoitinta, joka on varattu tälle pinolle). bool b = tosi; // varattu pinolle. jos (b) { // Luo 500 tavua pinoon hiilipuskuri [500]; // Luo 500 tavua kasaan pBuffer = uusi merkki [500]; } // <- puskuri on jaettu tähän, pBuffer ei } // <--- Hups, muistivuoto on olemassa, minun olisi pitänyt kutsua delete [] pBuffer; | Tärkein asia on, että kasa ja pino ovat yleisiä termejä tavoille, joilla muisti voidaan allokoida. Ne voidaan toteuttaa monin eri tavoin, ja termit koskevat peruskäsitteitä. Esineiden pinossa tavarat istuvat päällekkäin siinä järjestyksessä kuin ne on sijoitettu sinne, ja voit poistaa vain ylemmän(kaatamatta koko asiaa). Pino on yksinkertainen siinä, että sinun ei tarvitse ylläpitää taulukkoa, joka sisältää tietueen jokaisesta kohdennetun muistin osasta; ainoa tarvitsemasi tilatieto on yksi osoitin pinon loppuun. Voit jakaa ja poistaa varauksen vain lisäämällä ja vähentämällä kyseistä osoitinta. Huomaa: Pino voidaan joskus toteuttaa aloittamaan muistiosan yläosasta ja ulottumaan alaspäin eikä kasvavan ylöspäin. Kasassa ei ole erityistä järjestystä tavaroille. Voit tavoittaa tavarat ja poistaa ne missä tahansa järjestyksessä, koska selkeää 'ylintä' kohdetta ei ole. Kasan allokointi vaatii täydellisen kirjanpidon siitä, mikä muisti on jaettu ja mikä ei, samoin kuin joitain yleishuoltoa, jotta voidaan vähentää pirstoutumista, löytää vierekkäiset muistisegmentit riittävän suuriksi sopimaan pyydettyyn kokoon jne. Muisti voidaan jakaa milloin tahansa jättäen vapaata tilaa. Joskus muistinjakolaite suorittaa huoltotehtäviä, kuten eheyttää muistia siirtämällä allokoitua muistia, tai roskien keräys - tunnistaa ajon aikana, kun muisti ei ole enää kattava, ja jakaa sen. Näiden kuvien pitäisi tehdä melko hyvä tehtävä kuvata kahta tapaa jakaa ja vapauttaa muistia pinossa ja kasassa. Yum! Missä määrin niitä ohjaa käyttöjärjestelmä tai kielen ajonaika? Kuten mainittiin, kasa ja pino ovat yleisiä termejä, ja ne voidaan toteuttaa monin tavoin. Tietokoneohjelmissa on tyypillisesti pino, jota kutsutaan puhelupinoksi, joka tallentaa nykyisen toiminnon kannalta merkityksellisen tiedon, kuten osoittimen mihin tahansa toimintoon, josta sitä kutsuttiin, ja kaikki paikalliset muuttujat. Koska toiminnot kutsuvat muita toimintoja ja palaavat sitten, pino kasvaa ja kutistuu pitääkseen tietoja toiminnoista, jotka ovat puhelupinon alapuolella. Ohjelmalla ei todellakaan ole ajon hallintaa; sen määräävät ohjelmointikieli, käyttöjärjestelmä ja jopa järjestelmäarkkitehtuuri. Kasa on yleinen termi, jota käytetään mihin tahansa muistiin, joka varataan dynaamisesti ja satunnaisesti; ts. epäkunnossa. Muisti on tyypillisesti käyttöjärjestelmän varaama, ja sovellus kutsuu API-toimintoja tämän varauksen suorittamiseksi. Dynaamisesti allokoidun muistin hallinnassa tarvitaan melko vähän yleiskustannuksia, jotka yleensä hoidetaan käytetyn ohjelmointikielen tai ympäristön ajonaikaisella koodilla. Mikä on niiden soveltamisala? Puhelupino on niin matalan tason käsite, että se ei liity 'laajuuteen' ohjelmoinnin kannalta. Jos purat osan koodista, näet suhteelliset osoittimen tyyliviittaukset pinon osiin, mutta korkeamman tason kielen osalta kieli asettaa omat soveltamisasetuksensa. Yksi tärkeä osa pinosta on kuitenkin se, että kun funktio palaa, kaikki toiminnolle paikalliset vapautetaan välittömästi pinosta. Se toimii samalla tavalla kuin odotat sen toimivan, kun otetaan huomioon, kuinka ohjelmointikielesi toimivat. Kasassa sitä on myös vaikea määritellä. Laajuus on mikä tahansa käyttöjärjestelmän paljastama, mutta ohjelmointikielesi todennäköisesti lisää sääntöjään siitä, mikä "laajuus" on sovelluksessasi. Suoritinarkkitehtuuri ja käyttöjärjestelmä käyttävät virtuaalista osoitetta, jonka prosessori kääntää fyysisiksi osoitteiksi ja sivuissa on vikoja jne. He seuraavat kirjaa siitä, mitkä sivut kuuluvat mihin sovelluksiin. Sinun ei kuitenkaan tarvitse koskaan huolehtia tästä, koska käytät vain mitä menetelmää ohjelmointikielesi käyttää varaamaan ja vapauttamaan muistia ja tarkistamaan virheet (jos allokointi / vapauttaminen epäonnistuu jostain syystä). Mikä määrittää kunkin koon? Jälleen, se riippuu kielestä, kääntäjästä, käyttöjärjestelmästä ja arkkitehtuurista. Pino on yleensä varattu ennalta, koska määritelmän mukaan sen on oltava vierekkäistä muistia. Kielen kääntäjä tai käyttöjärjestelmä määrää sen koon. Et tallenna pinoon valtavia paloja, joten se on tarpeeksi suuri, jotta sitä ei koskaan pitäisi käyttää kokonaan, paitsi ei-toivottuja loputtomia rekursioita (täten "pinon ylivuotoa") tai muita epätavallisia ohjelmointipäätöksiä varten. Kasa on yleinen termi kaikelle, mikä voidaan dynaamisesti allokoida. Riippuen siitä, miten katsot sitä, se muuttaa kokoaan jatkuvasti. Nykyaikaisissa prosessoreissa ja käyttöjärjestelmissä tarkka tapa toimia on joka tapauksessa hyvin abstrakti, joten sinun ei yleensä tarvitse huolehtia paljon siitä, miten se toimii syvällä, paitsi että (kielillä, joiden avulla voit), et saa käyttää muistia, joka et ole vielä jakanut tai vapauttanut muistia. Mikä tekee siitä nopeamman? Pino on nopeampi, koska kaikki vapaa muisti on aina vierekkäistä. Kaikkia vapaan muistin segmenttejä ei tarvitse ylläpitää, vain yksi osoitin pinon nykyiselle yläosalle. Kääntäjät yleensä tallentavat tämän osoittimen erityiseen, nopeaan rekisteriin tätä tarkoitusta varten. Lisäksi seuraavat pino-operaatiot keskittyvät yleensä hyvin lähellä oleville muistialueille, mikä on hyvin matalalla tasolla prosessorin optimoimiseksivälimuistit. | (Olen siirtänyt tämän vastauksen toisesta kysymyksestä, joka oli enemmän tai vähemmän tämän kysymyksen huijaus.) Vastaus kysymykseesi on toteutuskohtainen ja voi vaihdella kääntäjien ja prosessoriarkkitehtuurien välillä. Tässä on kuitenkin yksinkertaistettu selitys. Sekä pino että kasa ovat muistialueita, jotka on allokoitu alla olevasta käyttöjärjestelmästä (usein virtuaalimuisti, joka on kartoitettu fyysiseen muistiin tarpeen mukaan). Monisäikeisessä ympäristössä jokaisella säikeellä on oma täysin itsenäinen pino, mutta he jakavat kasan. Samanaikaista pääsyä on ohjattava kasalla, eikä se ole mahdollista pinossa. Kasa Kasa sisältää linkitetyn luettelon käytetyistä ja ilmaisista lohkoista. Kasan uudet varaukset (uudella tai mallocilla) täyttyvät luomalla sopiva lohko yhdestä vapaista lohkoista. Tämä edellyttää kasan lohkoluettelon päivittämistä. Nämä metatiedot kasan lohkoista tallennetaan myös kasaan usein pienelle alueelle jokaisen lohkon eteen. Kasan kasvaessa uusia lohkoja varataan usein alemmista osoitteista suurempiin osoitteisiin. Siksi voit ajatella kasaa muistilohkojen kasana, joka kasvaa kooltaan muistia kohdennettaessa. Jos kasa on liian pieni varausta varten, kokoa voidaan usein kasvattaa hankkimalla lisää muistia taustalla olevasta käyttöjärjestelmästä. Monien pienten lohkojen jakaminen ja jakaminen voi jättää kasan tilaan, jossa käytettyjen lohkojen välissä on paljon pieniä vapaita lohkoja. Pyyntö suuren lohkon varaamiseksi voi epäonnistua, koska mikään vapaista lohkoista ei ole riittävän suuri allokointipyynnön tyydyttämiseksi, vaikka vapaiden lohkojen yhdistetty koko voi olla riittävän suuri. Tätä kutsutaan kasan pirstoutumiseksi. Kun käytetty lohko, joka on vapaan lohkon vieressä, jaetaan, uusi vapaa lohko voidaan yhdistää viereiseen vapaaseen lohkoon suuremman vapaan lohkon luomiseksi, mikä vähentää tehokkaasti kasan pirstoutumista. Pino Pino toimii usein rinnakkain erityisen prosessorin erityisen rekisterin kanssa, nimeltään pinon osoitin. Aluksi pinon osoitin osoittaa pinon yläosaan (pinon korkein osoite). CPU: lla on erityisohjeet arvojen työntämiseen pinoon ja niiden palauttamiseen pinosta. Jokainen painallus tallentaa arvon pinon osoittimen nykyiseen sijaintiin ja pienentää pinon osoitinta. Pop hakee pinon osoittimen osoittaman arvon ja lisää sitten pinon osoitinta (älä hämmenty siitä, että arvon lisääminen pinoon pienentää pinon osoitinta ja arvon poistaminen lisää sitä. Muista, että pino kasvaa pohja). Tallennetut ja haetut arvot ovat CPU-rekisterien arvoja. Kun toimintoa kutsutaan, keskusyksikkö käyttää erityisiä ohjeita, jotka työntävät nykyistä käskyosoitinta, eli pinolle suoritettavan koodin osoitetta. CPU hyppää sitten toimintoon asettamalla käskyosoitin kutsutun toiminnon osoitteeseen. Myöhemmin, kun toiminto palaa, vanha käskyosoitin ponnahtaa pinosta ja suoritus jatkuu koodissa heti kutsun jälkeen funktiolle. Kun funktio syötetään, pinon osoitinta pienennetään, jotta pinossa olisi enemmän tilaa paikallisille (automaattisille) muuttujille. Jos funktiossa on yksi paikallinen 32-bittinen muuttuja, pinoon varataan neljä tavua. Kun toiminto palaa, pinon osoitin siirretään takaisin vapauttamaan varattu alue. Jos toiminnolla on parametreja, ne työnnetään pinoon ennen kutsua funktiolle. Funktion koodi pystyy sitten siirtymään pinosta nykyisestä pinon osoittimesta näiden arvojen löytämiseksi. Pesimistoiminnon puhelut toimivat kuin viehätys. Jokainen uusi kutsu jakaa toimintoparametrit, paluuosoitteen ja tilan paikallisille muuttujille, ja nämä aktivointitietueet voidaan pinota sisäkkäisillä puheluilla ja ne purkautuvat oikealla tavalla, kun toiminnot palaavat. Koska pino on rajoitettu muistilohko, voit aiheuttaa pinon ylivuotoa kutsumalla liian monta sisäkkäistä toimintoa ja / tai varaamalla liikaa tilaa paikallisille muuttujille. Usein pinoon käytetty muistialue on asetettu siten, että kirjoittaminen pinon pohjan (alimman osoitteen) alle laukaisee ansan tai poikkeuksen suorittimessa. Tämä poikkeuksellinen tila voidaan sitten saada ajon aikana kiinni ja muuntaa jonkinlaiseksi pinon ylivuotopoikkeukseksi. Voiko kasaan varata toiminnon pinon sijaan? Ei, toimintojen aktivointitietueet (ts. Paikalliset tai automaattiset muuttujat) allokoidaan pinolle, jota käytetään paitsi näiden muuttujien tallentamiseen myös sisäkkäisten toimintokutsujen seuraamiseen. Kuinka kasa hoidetaan, riippuu ajonaikaisesta ympäristöstä. C käyttää mallocia ja C ++ käyttää uutta, mutta monilla muilla kielillä on roskat. Pino on kuitenkin matalamman tason ominaisuus, joka on läheisesti sidottu prosessorin arkkitehtuuriin. Kasan kasvaminen silloin, kun tilaa ei ole tarpeeksi, ei ole siitä lähtien liian kovaase voidaan toteuttaa kirjaston puhelussa, joka käsittelee kasaa. Pinon kasvattaminen on kuitenkin usein mahdotonta, koska pinon ylivuoto havaitaan vasta, kun on liian myöhäistä; ja suorituslangan sulkeminen on ainoa toteuttamiskelpoinen vaihtoehto. | Seuraavassa C # -koodissa public void Menetelmä 1 () { int i = 4; int y = 2; luokka1 cls1 = uusi luokka1 (); } Näin muistia hallitaan Paikalliset muuttujat, joiden on kestettävä vain niin kauan kuin funktion kutsu menee pinoon. Kasaa käytetään muuttujiin, joiden elinaikaa emme oikeastaan tiedä etukäteen, mutta odotamme niiden kestävän jonkin aikaa. Useimmilla kielillä on kriittistä, että tiedämme kääntöhetkellä kuinka suuri muuttuja on, jos haluamme tallentaa sen pinoon. Esineet (joiden koko vaihtelee päivitettäessä) menee kasaan, koska emme tiedä luontihetkellä kuinka kauan ne kestävät. Monilla kielillä kasa on roskaa, jota kerätään sellaisten esineiden (kuten cls1-objektin) löytämiseksi, joille ei ole enää viitteitä. Java-ohjelmassa suurin osa esineistä menee suoraan kasaan. C / C ++: n kaltaisilla kielillä rakenteet ja luokat voivat usein jäädä pinoon, kun et käsittele osoittimia. Lisätietoja löytyy täältä: Ero pinon ja kasan muistin allokoinnin välillä «timmurphy.org ja täällä: Objektien luominen pinoon ja kasaan Tämä artikkeli on yllä olevan kuvan lähde: Kuusi tärkeää .NET-käsitettä: Pino, kasa, arvotyypit, viitetyypit, nyrkkeily ja unboxing - CodeProject mutta muista, että se voi sisältää joitain epätarkkuuksia. | Pino Kun soitat funktiolle, kyseisen funktion argumentit ja jokin muu yleiskustannus laitetaan pinoon. Joitakin tietoja (kuten mihin mennä takaisin) tallennetaan myös sinne. Kun ilmoitat muuttujan funktion sisällä, kyseinen muuttuja varataan myös pinoon. Pinon jakaminen on melko yksinkertaista, koska jaat aina päinvastaisessa järjestyksessä kuin varaat. Pino tavaraa lisätään, kun syötät toimintoja, vastaavat tiedot poistetaan, kun poistut niistä. Tämä tarkoittaa, että sinulla on tapana pysyä pienellä pinon alueella, ellet soita paljon toimintoja, jotka kutsuvat paljon muita toimintoja (tai luovat rekursiivisen ratkaisun). Kasa Kasa on yleisnimi sille, mihin laitat luomasi tiedot lennossa. Jos et tiedä kuinka monta avaruusalusta ohjelmasi aikoo luoda, käytät todennäköisesti uutta (tai malloc- tai vastaavaa) operaattoria kunkin avaruusaluksen luomiseen. Tämä jako pysyy paikallaan jonkin aikaa, joten todennäköisesti vapautamme asiat eri järjestyksessä kuin luomme ne. Niinpä kasa on paljon monimutkaisempi, koska loppujen lopuksi on muistialueita, jotka ovat käyttämättömiä lomitettuna palojen kanssa - muisti pirstaloituu. Tarvitsemasi koon vapaan muistin löytäminen on vaikea ongelma. Siksi kasaa tulisi välttää (vaikka sitä käytetään edelleen usein). Toteutus Sekä pinon että kasan toteutus riippuu yleensä ajonaikaisesta käyttöjärjestelmästä. Usein pelit ja muut suorituskyvyn kannalta kriittiset sovellukset luovat omat muistiratkaisunsa, jotka tarttuvat suureen osaan muistia kasasta ja laittavat sen sitten sisäisesti välttääkseen käyttöjärjestelmän muistiin luottamisen. Tämä on käytännöllistä vain, jos muistisi käyttö poikkeaa normaalisti - ts. Peleissä, joissa lataat tason yhdellä valtavalla operaatiolla ja voit viedä koko erän toiseen valtavaan operaatioon. Fyysinen sijainti muistissa Tämä on vähemmän merkitystä kuin luulet virtuaalimuistiksi kutsutun tekniikan vuoksi, joka saa ohjelmasi ajattelemaan, että sinulla on pääsy tiettyyn osoitteeseen, jossa fyysiset tiedot ovat muualla (jopa kiintolevyllä!) Pinoa varten saadut osoitteet ovat kasvavassa järjestyksessä, kun puhelupuu syvenee. Kasan osoitteet ovat ennustamattomia (ts. Toteutuskohtaisia), ja rehellisesti sanottuna ne eivät ole tärkeitä. | Selvyyden vuoksi tällä vastauksella on virheellisiä tietoja (Thomas korjasi vastauksensa kommenttien jälkeen, siisti :)). Muut vastaukset välttävät vain selittämästä, mitä staattinen allokointi tarkoittaa. Joten selitän kolme pääasiallista allokointimuotoa ja miten ne yleensä liittyvät alla olevaan kasaan, pinoon ja data-segmenttiin. Esitän myös joitain esimerkkejä sekä C / C ++: ssa että Pythonissa auttaakseni ihmisiä ymmärtämään. "Staattisia" (AKA staattisesti allokoituja) muuttujia ei ole varattu pinoon. Älä oleta niin - monet ihmiset tekevät vain siksi, että "staattinen" kuulostaa paljon kuin "pino". Ne eivät todellakaan ole pinossa eikä kasassa. Ne ovat osa ns. Tietosegmenttiä. On kuitenkin yleensä parempi harkita "soveltamisalaa" ja "elinikää" eikä "pinoa" ja "kasaa". Laajuus viittaa siihen, mitkä koodin osat voivat käyttää muuttujaa. Yleensä ajattelemme paikallista laajuutta (pääsee vain nykyisen toiminnon kautta) vs. globaalia laajuutta (voidaan käyttää missä tahansa), vaikka laajuus voi olla paljon monimutkaisempi. Elinikä tarkoittaa, kun muuttuja allokoidaan ja jaetaan ohjelman suorituksen aikana. Yleensä ajattelemme staattista allokointia (muuttujasäilyy koko ohjelman ajan, mikä tekee siitä hyödyllisen samojen tietojen tallentamiseksi useaan toimintokutsuun) verrattuna automaattiseen allokointiin (muuttuja jatkuu vain yhden toiminnon kutsun aikana, mikä tekee siitä hyödyllisen vain sellaisten tietojen tallentamiseen, joita käytetään vain funktio ja voidaan hylätä, kun olet valmis) verrattuna dynaamiseen allokointiin (muuttujat, joiden kesto määritetään ajon aikana, eikä kääntöaikaa, kuten staattinen tai automaattinen). Vaikka useimmat kääntäjät ja tulkit toteuttavat tämän käyttäytymisen samalla tavalla pinojen, kasojen jne. Käytössä, kääntäjä voi joskus rikkoa näitä käytäntöjä, jos se haluaa, kunhan käyttäytyminen on oikein. Esimerkiksi optimoinnin vuoksi paikallinen muuttuja voi olla vain rekisterissä tai se voidaan poistaa kokonaan, vaikka suurin osa paikallisista muuttujista on pinossa. Kuten muutamissa kommenteissa on todettu, voit vapaasti toteuttaa kääntäjän, joka ei edes käytä pinoa tai kasaa, vaan sen sijaan joitain muita tallennusmekanismeja (harvoin tehty, koska pinot ja kasat sopivat tähän hyvin). Annan yksinkertaisen kommentoidun C-koodin tämän kaiken havainnollistamiseksi. Paras tapa oppia on suorittaa ohjelma virheenkorjaimen alla ja seurata käyttäytymistä. Jos haluat lukea mieluummin pythonia, siirry vastauksen loppuun :) // Staattisesti varattu datasegmenttiin, kun ohjelma / DLL ladataan ensimmäisen kerran // Jaettu, kun ohjelma / DLL poistuu // soveltamisala - pääsee mihin tahansa koodin kohtaan int someGlobalVariable; // Staattisesti varattu datasegmenttiin, kun ohjelma ladataan ensimmäisen kerran // Jaettu, kun ohjelma / DLL poistuu // soveltamisala - pääsee mistä tahansa tässä kooditiedostossa staattinen int someStaticVariable; // "someArgument" allokoidaan pinolle aina, kun MyFunction kutsutaan // "someArgument" jaetaan, kun MyFunction palaa // soveltamisala - pääsee vain MyFunction () -sivulle void MyFunction (int someArgument) { // Staattisesti varattu datasegmenttiin, kun ohjelma ladataan ensimmäisen kerran // Jaettu, kun ohjelma / DLL poistuu // soveltamisala - pääsee vain MyFunction () static int someLocalStaticVariable; // Varattu pinoon joka kerta, kun MyFunction kutsutaan // Jaettu, kun MyFunction palaa // soveltamisala - pääsee vain MyFunction () -sivulle int someLocalVariable; // Ainoa osoitin pinolle varataan joka kerta, kun MyFunction kutsutaan // Tämä osoitin jaetaan, kun MyFunction palaa // soveltamisala - osoitinta voi käyttää vain MyFunctionissa () int * someDynamicVariable; // Tämä rivi saa aikaan kokonaisluvun varaamisen kasaan // kun tämä rivi suoritetaan. Huomaa, että tämä ei ole vuoden alussa // kutsu MyFunction (), kuten automaattiset muuttujat // kattavuus - vain MyFunction (): n koodi voi käyttää tätä tilaa // * tämän tietyn muuttujan * kautta. // Jos kuitenkin välität osoitteen muualle, kyseinen koodi // voi käyttää sitä myös someDynamicVariable = uusi int; // Tämä rivi jakaa tilan kasan kokonaisluvulle. // Jos emme kirjoittaneet sitä, muisti "vuotaa". // Huomaa olennainen ero pinon ja kasan välillä // kasaa pitää hallita. Pino hoidetaan meille. poista someDynamicVariable; // Muissa tapauksissa sen sijaan, että jaoit tämän kasan tilaa sinulle // saattaa tallentaa osoitteen pysyvämpään käytettäväksi myöhemmin. // Jotkut kielet huolehtivat jopa jakelusta sinulle ... mutta // aina siitä on huolehdittava ajon aikana jollakin mekanismilla. // Kun funktio palaa, someArgument, someLocalVariable // ja osoitin someDynamicVariable jaetaan. // space, johon jotkutDynamicVariable viittasivat, oli jo // jaettu ennen paluuta. palata; } // Huomaa, että jotkutGlobalVariable, jotkutStaticVariable ja // someLocalStaticVariable on edelleen olemassa eikä ole // jaettu, kunnes ohjelma poistuu. Erityisen kirkas esimerkki siitä, miksi on tärkeää erottaa käyttöikä ja laajuus, on se, että muuttujalla voi olla paikallinen laajuus, mutta staattinen käyttöikä - esimerkiksi "someLocalStaticVariable" yllä olevassa koodinäytteessä. Tällaiset muuttujat voivat tehdä tavallisista mutta epävirallisista nimeämistavoistamme hyvin hämmentäviä. Esimerkiksi kun sanomme "paikallinen", tarkoitamme yleensä "paikallisesti määriteltyä automaattisesti allokoitua muuttujaa" ja kun sanomme globaali, tarkoitamme yleensä "globaalisti määriteltyä staattisesti allokoitua muuttujaa". Valitettavasti, kun on kyse sellaisista asioista kuin "tiedostotyyppiset staattisesti varatut muuttujat", monet ihmiset vain sanovat ... "huh ???". Jotkut C / C ++: n syntaksivalinnoista pahentavat tätä ongelmaa - esimerkiksi monet ihmiset ajattelevat, että globaalit muuttujat eivät ole "staattisia" alla esitetyn syntaksin takia. int var1; // Sisältää globaalin laajuuden ja staattisen allokoinnin staattinen int var2; // Tiedoston laajuus ja staattinen allokointi int main () {return 0;} Huomaa, että avainsanan "staattinen" lisääminen yllä olevaan ilmoitukseen estää var2: n globaalin laajuuden. Globaalilla var1: llä on kuitenkin staattinen allokointi. Tämä ei oleintuitiivinen! Tästä syystä yritän koskaan käyttää sanaa "staattinen" kuvaellessani laajuutta ja sanoa sen sijaan jotain "tiedosto" tai "tiedosto rajoitettu". Kuitenkin monet ihmiset käyttävät ilmausta "staattinen" tai "staattinen laajuus" kuvaamaan muuttujaa, johon pääsee vain yhdestä kooditiedostosta. Elinkaaren aikana "staattinen" tarkoittaa aina, että muuttuja varataan ohjelman alkaessa ja jaetaan, kun ohjelma poistuu. Jotkut ihmiset ajattelevat näiden käsitteiden olevan C / C ++ -spesifisiä. Ne eivät ole. Esimerkiksi alla oleva Python-näyte kuvaa kaikkia kolmea allokointityyppiä (tulkituissa kielissä on joitain hienovaraisia eroja, joihin en pääse täällä). päivämäärän tuonnista päivämäärä luokan eläin: _FavoriteFood = 'Määrittelemätön' # _FavoriteFood on kohdistettu staattisesti def PetAnimal (itse): curTime = päivämäärä.aika (datetime.now ()) # curTime varataan automaattisesti tulosta ("Kiitos hyväilemisestäni. Mutta se on" + str (curTime) + ", sinun pitäisi ruokkia minua. Suosikkiruokani on" + self._FavoriteFood) luokka Kissa (eläin): _FavoriteFood = 'tonnikala' # Huomaa, että koska ohitamme, Cat-luokassa on oma staattisesti varattu _FavoriteFood-muuttuja, joka eroaa eläinten luokan koira (eläin): _FavoriteFood = 'steak' # Samoin Koiraluokka saa oman staattisen muuttujan. Tärkeää huomata - tämä yksi staattinen muuttuja on jaettu kaikille Dog-esiintymille, joten se ei ole dynaaminen! jos __nimi__ == "__main__": whiskers = Kissa () # Dynaamisesti varattu fido = Koira () # Dynaamisesti varattu rinTinTin = Koira () # Dynaamisesti varattu poskiparta.PetAnimal () fido.PetAnimal () rinTinTin.PetAnimal () Dog._FavoriteFood = 'maitoluut' poskiparta.PetAnimal () fido.PetAnimal () rinTinTin.PetAnimal () # Tuotos on: # Kiitos hyväilemästä minua. Mutta se on 13: 05: 02.255000, sinun pitäisi ruokkia minua. Lempiruokani on tonnikala # Kiitos hyväilemästä minua. Mutta se on 13: 05: 02.255000, sinun pitäisi ruokkia minua. Lempiruokani on pihvi # Kiitos hyväilemästä minua. Mutta se on 13: 05: 02.255000, sinun pitäisi ruokkia minua. Lempiruokani on pihvi # Kiitos hyväilemästä minua. Mutta se on 13: 05: 02.255000, sinun pitäisi ruokkia minua. Lempiruokani on tonnikala # Kiitos hyväilemästä minua. Mutta se on 13: 05: 02.255000, sinun pitäisi ruokkia minua. Lempiruokani on maitoluut # Kiitos hyväilemästä minua. Mutta se on 13: 05: 02.256000, sinun pitäisi ruokkia minua. Lempiruokani on maitoluut | Toiset ovat vastanneet laajaan aivohalvaukseen melko hyvin, joten heitän muutamia yksityiskohtia. Pinon ja kasan ei tarvitse olla yksikkö. Yleinen tilanne, jossa sinulla on enemmän kuin yksi pino, on, jos sinulla on useampi kuin yksi ketju prosessissa. Tässä tapauksessa jokaisella langalla on oma pino. Sinulla voi olla myös useampia kasoja, esimerkiksi jotkut DLL-kokoonpanot voivat johtaa siihen, että eri DLL-tiedostot allokoidaan eri kasoista, minkä vuoksi on yleensä huono idea vapauttaa toisen kirjaston varaama muisti. C: ssä voit saada vaihtelevan pituisen allokoinnin hyödyn käyttämällä pinoa kohdentavaa allokaa, toisin kuin kasaan allokointia. Tämä muisti ei selviä palautuslausekkeestasi, mutta se on hyödyllinen raaputuspuskurille. Suuren väliaikaisen puskurin luominen Windowsille, jota et käytä paljon, ei ole ilmaista. Tämä johtuu siitä, että kääntäjä luo pinon koetussilmukan, jota kutsutaan joka kerta, kun toiminto syötetään varmistaakseen, että pino on olemassa (koska Windows käyttää pinon lopussa yhtä suojaussivua havaitsemaan, milloin sen on kasvatettava pinoa. Jos käytät muistia useammalla kuin yhdellä sivulla pinon päädystä, kaatut. Esimerkki: mitätöi toimintani () { hiili iso [10000000]; // Tee jotain, joka käyttää vain ensimmäistä 1 000: ta suurta 99% ajasta. } | Toiset ovat suoraan vastanneet kysymykseesi, mutta yritettäessä ymmärtää pinoa ja kasaa on mielestäni hyödyllistä ottaa huomioon perinteisen UNIX-prosessin muistiasettelu (ilman säikeitä ja mmap () -pohjaisia allokaattoreita). Muistinhallinnan sanaston verkkosivulla on kaavio tästä muistiasettelusta. Pino ja kasa sijaitsevat perinteisesti prosessin virtuaalisen osoitetilan vastakkaisissa päissä. Pino kasvaa automaattisesti, kun sitä käytetään, ytimen asettamaan kokoon (jota voidaan säätää setrlimitillä (RLIMIT_STACK, ...)). Kasa kasvaa, kun muistinvaraaja kutsuu brk () - tai sbrk () -järjestelmäkutsun, kartoittamalla lisää fyysisen muistin sivuja prosessin virtuaaliseen osoiteavaruuteen. Järjestelmissä, joissa ei ole virtuaalimuistia, kuten joissakin sulautetuissa järjestelmissä, käytetään usein samaa perusasettelua, paitsi että pino ja kasa ovat kiinteitä. Muissa sulautetuissa järjestelmissä (kuten Microchip PIC -mikrokontrollereihin perustuvissa) ohjelmapino on erillinen muistilohko, johon ei voida kohdistaa tiedonsiirto-ohjeilla, ja jota voidaan muokata tai lukea epäsuorasti vain ohjelmavirtaohjeiden kautta (puhelu paluu jne.). Muilla arkkitehtuureilla, kuten Intel Itanium -prosessoreilla, on useita pinoja. Tässä mielessä pino on osa CPU-arkkitehtuuria. | Pino on osamuistia, jota voidaan käsitellä useiden avainkokoonpanokieliohjeiden avulla, kuten 'pop' (poista ja palauta arvo pinosta) ja 'push' (työnnä arvo pinoon), mutta myös soita (kutsu alirutiini - tämä palaa pinoon) ja palaa (palaa aliohjelmasta - tämä pudottaa osoitteen pinosta ja hyppää siihen). Se on pinon osoitinrekisterin alapuolella oleva muistialue, joka voidaan asettaa tarpeen mukaan. Pinoa käytetään myös argumenttien välittämiseen aliohjelmiin ja arvojen säilyttämiseen rekistereissä ennen aliohjelmien kutsumista. Kasa on osa muistia, jonka käyttöjärjestelmä antaa sovellukselle tyypillisesti syscallin, kuten mallocin kautta. Nykyaikaisissa käyttöjärjestelmissä tämä muisti on joukko sivuja, joihin vain soittoprosessilla on pääsy. Pinon koko määritetään ajon aikana, eikä se yleensä kasva ohjelman käynnistymisen jälkeen. C-ohjelmassa pinon on oltava riittävän suuri pitämään jokaisen funktion sisällä ilmoitetun muuttujan. Kasa kasvaa dynaamisesti tarpeen mukaan, mutta käyttöjärjestelmä on viime kädessä soittamassa (se kasvattaa usein kasaa enemmän kuin mallocin pyytämä arvo, jotta ainakin joidenkin tulevien mallocsien ei tarvitse palata ytimeen saada enemmän muistia. Tämä toiminto on usein muokattavissa) Koska olet jakanut pinon ennen ohjelman käynnistämistä, sinun ei tarvitse koskaan mallinoida ennen kuin voit käyttää pinoa, joten se on pieni etu siellä. Käytännössä on erittäin vaikea ennustaa, mikä on nopeaa ja mikä hidasta nykyaikaisissa käyttöjärjestelmissä, joissa on virtuaalimuistijärjestelmiä, koska miten sivut toteutetaan ja mihin ne on tallennettu, on toteutuksen yksityiskohtia. | Mikä on pino? Pino on esineiden kasa, tyypillisesti siististi järjestetty. Laskenta-arkkitehtuurien pinot ovat muistialueita, joihin tietoja lisätään tai poistetaan viimeinen ensin-ulos -muodolla. Monisäikeisessä sovelluksessa jokaisella säikeellä on oma pino. Mikä on kasa? Kasa on epäpuhdas kokoelma sattumanvaraisesti kasattuja asioita. Laskennallisissa arkkitehtuureissa kasa on dynaamisesti varatun muistin alue, jota käyttöjärjestelmä tai muistinhallintakirjasto hallinnoi automaattisesti. Kasan muisti varataan, jaetaan ja kootaan säännöllisesti ohjelman suorituksen aikana, mikä voi johtaa pirstoutumiseen. Sirpaloituminen tapahtuu, kun muistikohteille on varattu pieniä välilyöntejä, jotka ovat liian pieniä ylimääräisten muistikohteiden säilyttämiseksi. Nettotulos on prosenttiosuus kasatilasta, jota ei voida käyttää muille muistinvarauksille. Molemmat yhdessä Monisäikeisessä sovelluksessa jokaisella säikeellä on oma pino. Mutta kaikki erilaiset säikeet jakavat kasan. Koska eri säikeet jakavat kasan monisäikeisessä sovelluksessa, tämä tarkoittaa myös sitä, että säikeiden välillä on oltava jonkinlainen koordinointi, jotta ne eivät yritä käyttää ja käsitellä samaa kappaletta muistia samaan aikaan. Kumpi on nopeampi - pino vai kasa? Ja miksi? Pino on paljon nopeampi kuin kasa. Tämä johtuu tavasta, jolla muisti varataan pinoon. Muistin sijoittaminen pinoon on yhtä helppoa kuin pinon osoittimen siirtäminen ylöspäin. Niille, jotka ovat aloittaneet ohjelmoinnin, on todennäköisesti hyvä käyttää pinoa, koska se on helpompaa. Koska pino on pieni, haluat käyttää sitä, kun tiedät tarkalleen kuinka paljon muistia tarvitset tiedoillesi, tai jos tiedät, että tietojesi koko on hyvin pieni. On parempi käyttää kasaa, kun tiedät, että tarvitset paljon muistia tiedoihisi, tai et vain ole varma, kuinka paljon muistia tarvitset (kuten dynaamisen taulukon kanssa). Java-muistimalli Pino on muistialue, johon paikalliset muuttujat (mukaan lukien menetelmäparametrit) on tallennettu. Objektimuuttujien osalta nämä ovat vain viittauksia (osoittimia) kasan todellisiin kohteisiin. Joka kerta, kun kohde on instantioitu, varataan kasa muistia, joka pitää sisällään kyseisen objektin tiedot (tila). Koska objektit voivat sisältää muita objekteja, osa näistä tiedoista voi itse asiassa sisältää viitteitä näihin sisäkkäisiin kohteisiin. | Luulen, että monet muut ihmiset ovat antaneet sinulle enimmäkseen oikeita vastauksia tähän asiaan. Yksi huomiotta jäänyt yksityiskohta on kuitenkin se, että "kasaa" pitäisi itse asiassa kutsua "ilmaiseksi kaupaksi". Syynä tähän eroon on, että alkuperäinen ilmainen kauppa toteutettiin tietorakenteella, joka tunnetaan nimellä "binominen kasa". Tästä syystä varaaminen mallocin () / free () varhaisista toteutuksista tapahtui kasasta. Tänä nykypäivänä useimmat ilmaiset kaupat toteutetaan kuitenkin hyvin monimutkaisilla tietorakenteilla, jotka eivät ole binomisia kasoja. | Voit tehdä joitain mielenkiintoisia asioita pinolla. Esimerkiksi, sinulla on toimintoja, kuten alloka (olettaen, että voit ohittaa sen käyttöä koskevat runsaat varoitukset), joka on eräänlainen malloc, jokakäyttää muistiin nimenomaan pinoa, ei kasaa. Pinoihin perustuvat muistivirheet ovat kuitenkin pahimpia, mitä olen kokenut. Jos käytät kasan muistia ja ylität varatun lohkon rajat, sinulla on kohtuulliset mahdollisuudet laukaista segmenttivika. (Ei 100%: Lohkosi voi olla satunnaisesti vierekkäinen toisen kanssa, jonka olet aiemmin jakanut.) Mutta koska pinoon luodut muuttujat ovat aina vierekkäin, rajojen ulkopuolelle kirjoittaminen voi muuttaa toisen muuttujan arvoa. Olen oppinut, että aina kun tunnen, että ohjelmani on lakannut noudattamasta logiikan lakeja, se on todennäköisesti puskurin ylivuoto. | Yksinkertaisesti, pino on paikka, jossa paikalliset muuttujat luodaan. Joka kerta, kun soitat alirutiiniin, ohjelmalaskuri (osoitin seuraavaan konekäskyyn) ja kaikki tärkeät rekisterit, ja joskus parametrit työnnetään pinoon. Sitten kaikki aliohjelman sisällä olevat paikalliset muuttujat työnnetään pinoon (ja käytetään sieltä). Kun alirutiini on valmis, kaikki tavarat ponnahtaa takaisin pinosta. Tietokone- ja rekisteröintitiedot saavat ja laittaa takaisin sinne, missä ne olivat, kun ne ovat ponnahtaneet, joten ohjelmasi voi jatkaa hauskaa tietään. Kasa on muistin alue, jossa dynaamiset muistivaraukset tehdään (nimenomaiset "uudet" tai "allokoivat" puhelut). Se on erityinen tietorakenne, joka voi seurata erikokoisia muistilohkoja ja niiden allokoinnin tilaa. "Klassisissa" järjestelmissä RAM-muistia järjestettiin siten, että pinonosoitin alkoi muistin alaosasta, kasanosoitin alkoi ylhäältä ja ne kasvoivat toisiaan kohti. Jos ne ovat päällekkäisiä, sinulla ei ole RAM-muistia. Se ei kuitenkaan toimi nykyaikaisten monisäikeisten käyttöjärjestelmien kanssa. Jokaisella säikeellä on oltava oma pino, ja ne voidaan luoda dynaamisesti. | Lähettäjä WikiAnwser. Pino Kun funktio tai menetelmä kutsuu toista toimintoa, joka vuorostaan kutsuu toista toimintoa jne., Kaikkien näiden toimintojen suorittaminen pysyy keskeytettynä, kunnes viimeinen funktio palauttaa arvon. Tämä keskeytettyjen toimintakutsujen ketju on pino, koska pinon elementit (toimintokutsu) riippuvat toisistaan. Pino on tärkeää ottaa huomioon poikkeusten käsittelyssä ja langankäynnistyksissä. Pino Kasa on yksinkertaisesti muisti, jota ohjelmat käyttävät muuttujien tallentamiseen. Kasan elementillä (muuttujilla) ei ole riippuvuuksia toisistaan, ja siihen pääsee aina satunnaisesti milloin tahansa. | Pino Erittäin nopea pääsy Sinun ei tarvitse nimenomaisesti muuttaa muuttujia Keskusyksikkö hallitsee tilaa tehokkaasti, muisti ei pirstoutu Vain paikalliset muuttujat Rajoitus pinon kokoon (käyttöjärjestelmästä riippuva) Muuttujien kokoa ei voi muuttaa Pino Muuttujiin pääsee käsiksi maailmanlaajuisesti Muistikokoa ei ole rajoitettu (Suhteellisen) hitaampi pääsy Ei taattua tehokasta tilankäyttöä, muisti voi pirstaloitua ajan myötä, kun muistilohkot varataan ja vapautetaan Sinun on hallittava muistia (olet vastuussa muuttujien allokoinnista ja vapauttamisesta) Muuttujien kokoa voidaan muuttaa käyttämällä realloc () | Lyhyesti Pinoa käytetään staattiseen muistin allokointiin ja kasaa dynaamiseen muistin allokointiin, jotka molemmat on tallennettu tietokoneen RAM-muistiin. Yksityiskohtaisesti Pino Pino on "LIFO" (viimeinen sisään, ensin ulos) -tietorakenne, jota CPU hallinnoi ja optimoi melko tarkasti. Joka kerta, kun funktio ilmoittaa uuden muuttujan, se "työnnetään" pinoon. Sitten joka kerta, kun funktio poistuu, kaikki muuttujat, jotka tämä funktio on työntänyt pinoon, vapautetaan (eli ne poistetaan). Kun pinomuuttuja on vapautettu, kyseinen muistialue tulee saataville muille pinomuuttujille. Etuna pinon käytöstä muuttujien tallentamiseen on, että muistia hallitaan puolestasi. Sinun ei tarvitse jakaa muistia käsin tai vapauttaa sitä, kun et enää tarvitse sitä. Lisäksi, koska CPU järjestää pinomuistin niin tehokkaasti, pinomuuttujien lukeminen ja kirjoittaminen pinoon on erittäin nopeaa. Lisää löytyy täältä. Kasa Kasa on alue tietokoneen muistissa, jota ei hallita automaattisesti sinulle, eikä CPU hallinnoi sitä niin tiukasti. Se on vapaammin kelluva muistialue (ja on suurempi). Muistin jakamiseksi kasalle sinun on käytettävä malloc () - tai calloc () -ominaisuuksia, jotka ovat sisäänrakennettuja C-toimintoja. Kun olet jakanut muistia kasaan, olet vastuussa vapaan () käyttämisestä tämän muistin sijoittamiseen, kun et enää tarvitse sitä. Jos et tee tätä, ohjelmassasi on ns. Muistivuoto. Toisin sanoen kasan muisti varataan edelleen (eikä se ole muiden prosessien käytettävissä). Kuten näemme virheenkorjausosassa, on työkalu nimeltä Valgrind, joka voi auttaa sinua havaitsemaan muistivuodot. Toisin kuin pinossa, kasalla ei ole kokorajoituksia muuttuvalle koolle (lukuun ottamatta tietokoneen ilmeisiä fyysisiä rajoituksia). Kasan muisti on hieman hitaampi luettavaksi ja kirjoitettavaksi, koska kasan muistiin on käytettävä osoittimia. Puhumme viitteistä pian. Toisin kuin pino,kasaan luotuihin muuttujiin pääsee millä tahansa toiminnolla, missä tahansa ohjelmassa. Kekomuuttujat ovat pääosin globaalia. Lisää löytyy täältä. Pinoan varatut muuttujat tallennetaan suoraan muistiin, ja pääsy tähän muistiin on erittäin nopeaa, ja sen allokointi hoidetaan ohjelmaa koottaessa. Kun funktio tai menetelmä kutsuu toista toimintoa, joka vuorostaan kutsuu toista toimintoa jne., Kaikkien näiden toimintojen suorittaminen pysyy keskeytettynä, kunnes viimeinen funktio palauttaa arvon. Pino varataan aina LIFO-järjestyksessä, viimeisin varattu lohko on aina seuraava vapautettava lohko. Tämä tekee pinon seurannasta todella helppoa, lohkon vapauttaminen pinosta ei ole muuta kuin yhden osoittimen säätäminen. Kasalle varattujen muuttujien muisti on allokoitu ajoaikana ja tämän muistin käyttö on hieman hitaampaa, mutta kasan kokoa rajoittaa vain virtuaalimuistin koko. Kasan elementeillä ei ole riippuvuutta toisistaan, ja niihin pääsee aina satunnaisesti milloin tahansa. Voit jakaa lohkon milloin tahansa ja vapauttaa sen milloin tahansa. Tämä tekee paljon monimutkaisemmaksi seurata, mitkä kasan osat on varattu tai vapaa milloin tahansa. Voit käyttää pinoa, jos tiedät tarkalleen kuinka paljon tietoa sinun on jaettava ennen kääntöaikaa, eikä se ole liian iso. Voit käyttää kasaa, jos et tiedä tarkalleen kuinka paljon tietoa tarvitset ajon aikana tai jos sinun on allokoitava paljon dataa. Monisäikeisessä tilanteessa jokaisella langalla on oma täysin itsenäinen pino, mutta ne jakavat kasan. Pino on lankakohtainen ja kasa on sovelluskohtainen. Pino on tärkeää ottaa huomioon poikkeusten käsittelyssä ja langankäynnistyksissä. Jokainen säie saa pinon, kun taas sovellukselle on tyypillisesti vain yksi kasa (vaikka ei ole harvinaista, että useita kasoja erityyppisille allokoinnille). Jos sovellus tarvitsee ajon aikana enemmän kasaa, se voi allokoida muistia vapaasta muistista ja jos pino tarvitsee muistia, se voi jakaa muistia sovelluksen vapaasta muistista. Jopa enemmän yksityiskohtia annetaan täällä ja täällä. Tule nyt kysymyksiisi vastauksiin. Missä määrin niitä ohjaa käyttöjärjestelmä tai kielen ajonaika? Käyttöjärjestelmä allokoi pinon jokaiselle järjestelmätason ketjulle, kun ketju luodaan. Tyypillisesti kielen ajonaikainen käyttöjärjestelmä kutsuu kasan varaamista sovellukselle. Lisää löytyy täältä. Mikä on niiden soveltamisala? Jo annettu alkuun. "Voit käyttää pinoa, jos tiedät tarkalleen kuinka paljon tietoa sinun on jaettava ennen kokoamisaikaa, eikä se ole liian suuri. Voit käyttää kasaa, jos et tiedä tarkalleen kuinka paljon tietoa tarvitset ajon aikana tai jos sinun on allokoitava paljon tietoja. " Lisää löytyy täältä. Mikä määrittää kunkin koon? Pino koon määrittää käyttöjärjestelmä, kun ketju luodaan. Kasan koko on asetettu sovelluksen käynnistyksen yhteydessä, mutta se voi kasvaa, kun tilaa tarvitaan (allokaattori pyytää lisää muistia käyttöjärjestelmästä). Mikä tekee siitä nopeamman? Pinon allokointi on paljon nopeampaa, koska kaikki, mitä se todella tekee, on pinon osoittimen siirtäminen. Muistivarastoja käyttämällä voit saada vertailukelpoisen suorituskyvyn kasan allokoinnista, mutta siihen liittyy pieni monimutkaisuus ja omat päänsäryt. Pino vs. kasa ei myöskään ole vain suorituskykyyn liittyvä näkökohta; se kertoo myös paljon esineiden odotetusta eliniästä. Yksityiskohdat löydät täältä. | OK, yksinkertaisesti ja lyhyillä sanoilla, ne tarkoittavat tilattua eikä tilattua ...! Pino: Pino-esineissä asiat nousevat päällekkäin, joten käsittely on nopeampaa ja tehokkaampaa! ... Joten aina on hakemisto, joka osoittaa tietyn kohteen, myös käsittely tulee olemaan nopeampaa, kohteiden välillä on myös suhde! ... Kasa: Ei tilausta, käsittely tapahtuu hitaammin ja arvot sekoitetaan ilman erityistä järjestystä tai hakemistoa ... satunnaisia ja niiden välillä ei ole yhteyttä ... joten suoritus ja käyttöaika voivat vaihdella ... Luon myös alla olevan kuvan osoittaakseni miltä ne voivat näyttää: | pino, kasa ja kunkin prosessin tiedot virtuaalimuistissa: | 1980-luvulla UNIX levitti kuin puput suurten yritysten pyörittäessä omaa. Exxonilla oli yksi, samoin kuin kymmeniä tuotemerkkejä menetti historiaan. Muistin sijoittaminen oli monien toteuttajien harkinnan mukaan. Tyypillinen C-ohjelma asetettiin tasaisesti muistiin mahdollisuus kasvaa muuttamalla brk () -arvoa. Tyypillisesti HEAP oli hieman alle tämän brk-arvon ja lisääntynyt brk lisäsi käytettävissä olevan kasan määrää. Yksittäinen pino oli tyypillisesti HEAP-alueen alapuolella oleva alue, joka oli muistialue sisältää mitään arvokasta seuraavan kiinteän muistilohkon yläosaan saakka. Tämä seuraava lohko oli usein CODE, jonka pinotiedot voivat korvata yhdessä aikakauden kuuluisimmista hakkeroista. Yksi tyypillinen muistilohko oli BSS (nollalohko)arvot) jota ei vahingossa nollattu yhden valmistajan tarjouksessa. Toinen oli DATA, joka sisälsi alustetut arvot, mukaan lukien merkkijonot ja numerot. Kolmas oli CODE, joka sisälsi CRT: n (C runtime), pääohjelman, toiminnot ja kirjastot. Virtuaalimuistin tulo UNIX: iin muuttaa monia rajoituksia. Ei ole mitään objektiivista syytä, miksi näiden lohkojen on oltava vierekkäisiä, tai kiinteä kokoinen tai tilattu tietyllä tavalla nyt. Tietysti ennen UNIXia oli Multics, joka ei kärsinyt näistä rajoituksista. Tässä on kaavio, joka esittää yhden aikakauden muistista. | Muutama sentti: Luulen, että on hyvä piirtää muistia graafisesti ja yksinkertaisemmin: Nuolet - osoittavat missä kasvaa pino ja kasa, prosessipinon koolla on käyttöjärjestelmässä määritetty raja, ketjupinon kokorajoitukset säikeiden luomisliittymän parametreilla Heap yleensä rajoittaa prosessin suurimman virtuaalimuistikoon, esimerkiksi 32-bittisille 2-4 Gt. Niin yksinkertainen tapa: prosessin kasa on yleinen prosessille ja kaikille sisäisille säikeille, käytetään muistin jakamiseen tavallisessa tilanteessa mallocin () kanssa. Pino on pikamuisti tavallisten tapauksien funktioiden palautusosoittimille ja muuttujille, jotka käsitellään parametreina funktiokutsussa, paikallisissa funktion muuttujissa. | Koska jotkut vastaukset menivät nokkelasti, aion lisätä punkkini. Yllättäen kukaan ei ole maininnut, että useita (eli eivät liity käynnissä olevien käyttöjärjestelmäketjujen lukumäärään) kutsuja löytyy paitsi eksoottisilla kielillä (PostScript) tai alustoilla (Intel Itanium) myös kuituissa, vihreissä säikeissä ja joitain korutiineja. Kuidut, vihreät langat ja korutiinit ovat monin tavoin samanlaisia, mikä aiheuttaa paljon sekaannusta. Ero kuitujen ja vihreiden säikeiden välillä on se, että ensimmäiset käyttävät yhteistyöhön perustuvaa moniajoa, kun taas jälkimmäiset voivat olla joko yhteistyöhön perustuvia tai ennakoivia (tai jopa molempia). Katso ero kuitujen ja korutiinien välillä tästä. Joka tapauksessa molempien kuitujen, vihreiden säikeiden ja korutiinien tarkoituksella on, että useita toimintoja suoritetaan samanaikaisesti, mutta ei rinnakkain (katso ero tästä SO-kysymyksestä) yhden käyttöjärjestelmän tason ketjussa, siirtäen ohjausta edestakaisin. järjestäytyneesti. Kun käytät kuituja, vihreitä lankoja tai korutiineja, sinulla on yleensä erillinen pino toimintoa kohden. (Teknisesti funktiona ei ole vain pino, vaan koko suorituskonteksti. Tärkeintä on, että CPU rekisteröi.) Jokaisessa säikeessä on niin monta pinoa kuin samanaikaisesti käynnissä olevia toimintoja, ja säie vaihtaa kunkin toiminnon välillä ohjelman logiikan mukaan. Kun funktio juoksee loppuun, sen pino tuhoutuu. Joten pinojen lukumäärä ja käyttöajat ovat dynaamisia, eikä niitä määrää OS-tason ketjujen määrä! Huomaa, että sanoin "yleensä erillinen pino toimintoa kohden". Couroutineja on sekä pinoissa että pinottomissa toteutuksissa. Merkittävimmät pinot C ++ -toteutukset ovat Boost.Coroutine ja Microsoft PPL: n asynkronointi / odottaa. (C ++ 17: n ehdotetut C ++: n jatkettavat toiminnot (eli "asynkronointi ja odotus") kuitenkin todennäköisesti käyttävät pinottomia korutiineja. Kuituehdotus C ++ -standardikirjastolle on tulossa. Lisäksi siellä on joitain kolmannen osapuolen kirjastoja. Vihreät säikeet ovat erittäin suosittuja kielillä, kuten Python ja Ruby. | Minulla on jotain jaettavaa, vaikka pääkohdat on jo käsitelty. Pino Erittäin nopea pääsy. Tallennettu RAM-muistiin. Toimintakutsu ladataan tänne yhdessä paikallisten muuttujien ja lähetettyjen toimintoparametrien kanssa. Tila vapautuu automaattisesti, kun ohjelma poistuu toiminta-alueelta. Tallennetaan peräkkäiseen muistiin. Pino Hidas pääsy verrattuna Stackiin. Tallennettu RAM-muistiin. Dynaamisesti luodut muuttujat tallennetaan tähän, mikä myöhemmin vaatii varatun muistin vapauttamisen käytön jälkeen. Tallennetaan kaikkialle, missä muistia kohdennetaan, osoitin käyttää sitä aina. Mielenkiintoinen huomautus: Jos toimintokutsut olisi tallennettu kasaan, siitä olisi tullut 2 sotkuista pistettä: Koska pino on peräkkäin tallennettu, suoritus on nopeampaa. Varasto kasaan olisi johtanut valtavaan ajankulutukseen, mikä olisi hidastanut koko ohjelman toteuttamista. Jos toiminnot olisi tallennettu kasaan (sotkuinen varastointi osoitin osoittaa), ei olisi ollut tapaa palata soittajan osoitteeseen takaisin (jonka pino antaa peräkkäisen muistin tallennuksen vuoksi). | Vau! Niin monta vastausta, enkä usko, että yksi heistä sai sen oikein ... 1) Missä ja mitä ne ovat (fyysisesti todellisen tietokoneen muistissa)? Pino on muisti, joka alkaa ohjelmakuvallesi osoitettuna suurimpana muistiosoitteena, ja sen arvo sen jälkeen vähenee. Se on varattu kutsutuille toimintoparametreille ja kaikille funktioissa käytetyille väliaikaisille muuttujille. On olemassa kaksi kasaa: julkinen ja yksityinen. Yksityinen kasa alkaa 16-tavun (64-bittiset ohjelmat) tai 8-tavun (32-bittiset-ohjelmat) rajasta ohjelman viimeisen tavun jälkeen, ja kasvaa sittenarvo sieltä. Sitä kutsutaan myös oletuskoneeksi. Jos yksityinen kasa tulee liian suureksi, se peittää pinon alueen, samoin kuin pino päällekkäin kasan, jos se tulee liian suureksi. Koska pino alkaa korkeammasta osoitteesta ja toimii tiensä alas pienempään osoitteeseen, asianmukaisella hakkeroinnilla voit saada pinon niin suureksi, että se ylittää yksityisen kasan alueen ja peittää koodialueen. Temppu on sitten limittää tarpeeksi koodialue, jonka voit liittää koodiin. Se on hieman hankala tehdä ja saatat uhata ohjelman kaatumisen, mutta se on helppoa ja tehokasta. Julkinen kasa sijaitsee omassa muistitilassa ohjelmakuvan ulkopuolella. Juuri tämä muisti viedään kiintolevylle, jos muistiresursseja on niukasti. 2) Missä määrin niitä ohjaa käyttöjärjestelmä tai kielen ajonaika? Pinoa ohjaa ohjelmoija, yksityistä kasaa hallinnoi käyttöjärjestelmä, eikä julkista kasaa kukaan hallitse, koska se on käyttöjärjestelmän palvelu - teet pyyntöjä ja joko ne hyväksytään tai evätään. 2b) Mikä on niiden soveltamisala? Ne ovat kaikki maailmanlaajuisia ohjelmassa, mutta niiden sisältö voi olla yksityistä, julkista tai globaalia. 2c) Mikä määrittää kunkin koon? Pino ja yksityisen kasan koko määräytyvät kääntäjän ajonaikavaihtoehdoista. Julkinen kasa alustetaan ajon aikana käyttämällä kokoparametria. 2d) Mikä tekee siitä nopeamman? Niitä ei ole suunniteltu nopeiksi, ne on suunniteltu hyödyllisiksi. Kuinka ohjelmoija käyttää niitä, määrittää, ovatko he "nopeita" vai "hitaita" VIITE: https://norasandler.com/2019/02/18/Write-a-Compiler-10.html https://docs.microsoft.com/en-us/windows/desktop/api/heapapi/nf-heapapi-getprocessheap https://docs.microsoft.com/en-us/windows/desktop/api/heapapi/nf-heapapi-heapcreate | Monet vastaukset ovat oikeita käsitteinä, mutta on huomattava, että laitteisto (eli mikroprosessori) tarvitsee pinon, jotta aliohjelmat voidaan kutsua (CALL kokoonpanokielellä ..). (OOP-kaverit kutsuvat sitä menetelmiksi) Pino tallentaa paluuosoitteet ja puhelu → push / ret → pop hallitaan suoraan laitteistolla. Voit käyttää pinoa parametrien välittämiseen .. vaikka se olisi hitaampaa kuin rekisterien käyttö (sanoisiko mikroprosessoriguru tai hyvä 1980-luvun BIOS-kirja ...) Mikään mikroprosessori ei voi toimia ilman pinoa. (emme voi kuvitella ohjelmaa edes kokoonpanokielellä ilman aliohjelmia / toimintoja) Ilman kasaa se voi. (Kokoonpanokieliohjelma voi toimia ilman, koska kasa on käyttöjärjestelmän käsite, malloc, eli OS / Lib-kutsu. Pinon käyttö on nopeampaa kuin: Onko laitteisto, ja jopa push / pop ovat erittäin tehokkaita. malloc edellyttää siirtymistä ydintilaan, käytä lukitusta / semaforia (tai muita synkronointiprimitiivejä) suorittamalla koodia ja hallitsemaan joitain rakenteita, joita tarvitaan varauksen seuraamiseen. | Kasa on dynaamisesti allokoidun muistin alue, jota käyttöjärjestelmä tai muistinhallintakirjasto hallinnoi automaattisesti. Voit jakaa lohkon milloin tahansa ja vapauttaa sen milloin tahansa. Kasan allokointi vaatii täydellisen kirjanpidon siitä, mikä muisti on jaettu ja mikä ei, samoin kuin joitain yleishuoltoa, jotta voidaan vähentää pirstoutumista, löytää vierekkäiset muistisegmentit riittävän suuriksi sopimaan pyydettyyn kokoon jne. Muisti voidaan jakaa milloin tahansa jättäen vapaata tilaa. Kasan kasvaessa uusia lohkoja varataan usein alemmista osoitteista suurempiin osoitteisiin. Siksi voit ajatella kasaa muistilohkojen kasana, joka kasvaa kooltaan muistia kohdennettaessa. Jos kasa on liian pieni varausta varten, kokoa voidaan usein kasvattaa hankkimalla lisää muistia taustalla olevasta käyttöjärjestelmästä. Kasasta varattu muisti pysyy varattu, kunnes jokin seuraavista tapahtuu: Muisti vapautuu Ohjelma päättyy Pino: Tallennetaan tietokoneen RAM-muistiin aivan kuin kasa. Pinoan luodut muuttujat poistuvat soveltamisalasta ja jaetaan automaattisesti. Paljon nopeampi allokoida kuin kasan muuttujat. Tallentaa parametrien välittämiseen käytetyt paikalliset tiedot, palautusosoitteet. Voi olla pinon ylivuoto, kun pinosta käytetään liikaa (enimmäkseen äärettömästä tai liian syvästä rekursiosta, erittäin suuret kohdennukset). Käytä pinoa, jos tiedät tarkalleen kuinka paljon tietoa tarvitset varaa ennen kokoamisaikaa, eikä se ole liian iso. Yleensä enimmäiskoko on jo määritetty ohjelmasi aikana alkaa. Pino: Tallennetaan tietokoneen RAM-muistiin aivan kuin pino. C ++: ssa kasan muuttujat on tuhottava manuaalisesti eikä koskaan jäävät soveltamisalan ulkopuolelle. Tiedot vapautetaan poistamalla, poistamalla [] tai ilmaiseksi. Hitaampi allokoida verrattuna pinon muuttujiin. Käytetään pyynnöstä tietolohkon allokoimiseksi ohjelman käyttöä varten. Voi olla pirstoutunutta, kun allokaatioita on paljon ja kauppapaikat. C ++: ssa tai C: ssä kasaan luodut tiedot osoittavat osoittimet ja jaetaan uudella tai mallocilla. Voi olla allokointivirheitä, jos liian suurta puskuria pyydetään voidaan jakaa. Sinäkäyttäisi kasaa, jos et tiedä tarkalleen kuinka paljon tietoja olet tarvitaan ajoaikana tai jos sinun on allokoitava paljon tietoja. Vastuussa muistivuodoista. | Pino on pohjimmiltaan helposti saatavilla oleva muisti, joka yksinkertaisesti hallitsee kohteita kuin - hyvin pino. Ainoastaan kohteet, joiden koko on tiedossa etukäteen, voivat mennä pinoon. Tämä pätee numeroihin, merkkijonoihin ja Boolean-arvoihin. Kasa on muisti kohteille, joiden et voi määrittää etukäteen tarkka koko ja rakenne. Koska esineitä ja taulukoita voidaan mutatoida ja Vaihda ajon aikana, heidän on mentävä kasaan. Lähde: Academind | Suorittimen pino ja kasa liittyvät fyysisesti siihen, kuinka prosessori ja rekisteröinnit toimivat muistin kanssa, miten koneen kokoonpanokieli toimii, eivät itse korkean tason kielet, vaikka nämä kielet voivatkin päättää pienistä asioista. Kaikki modernit suorittimet toimivat "saman" mikroprosessoriteorian kanssa: ne kaikki perustuvat niin kutsuttuihin "rekistereihin" ja jotkut ovat "pino" suorituskyvyn saavuttamiseksi. Kaikilla suorittimilla on alusta lähtien pinorekistereitä, ja ne olivat aina olleet täällä, tapa puhua, kuten tiedän. Kokoonpanokielet ovat samat alusta lähtien, huolimatta muunnelmista ... aina Microsoftiin ja sen välikieleen (IL) asti, joka muutti paradigman OO-virtuaalikoneen kokoonpanokieleksi. Joten voimme tulevaisuudessa saada jonkin verran CLI / CIL-prosessoria (yksi MS: n projekti). Suorittimilla on pinorekistereitä muistien käytön nopeuttamiseksi, mutta ne ovat rajalliset verrattuna muihin rekistereihin, jotta pääsy koko prosessin käytettävissä olevaan muistiin olisi täydellinen. Siksi puhuimme pinojen ja kasojen allokoinnista. Yhteenvetona voidaan todeta, että kasa on hudge ja hidas, ja se on tarkoitettu "globaaleille" instansseille ja esineiden sisällölle, koska pino on pieni ja nopea sekä "paikallisiin" muuttujiin ja viitteisiin (piilotetut osoittimet unohtamaan hallita niitä). Joten kun käytämme uutta avainsanaa menetelmässä, viite (int) luodaan pinoon, mutta esine ja kaikki sen sisältö (arvotyypit sekä objektit) luodaan kasaan, jos muistan. Mutta pinoon luodaan paikalliset perusarvotyypit ja taulukot. Ero muistin saannissa on soluviittaustasolla: kasan, prosessin kokonaismuistin, osoittaminen vaatii monimutkaisemman prosessorin rekisterien käsittelyssä kuin pino, joka on "enemmän" paikallisesti osoituksen suhteen, koska CPU-pino rekisteriä käytetään perusosoitteena, jos muistan. Siksi, kun meillä on hyvin pitkiä tai äärettömiä toistuvia puheluita tai silmukoita, saimme pinon ylivuotoa nopeasti jäädyttämättä järjestelmää nykyaikaisissa tietokoneissa ... C # Heap (ing) Vs Stack (ing) In .NET Pino vs kasa: tiedä ero Staattinen luokan muistin kohdistus, missä se on tallennettu C # Mitä ja missä pino ja kasa ovat? https://en.wikipedia.org/wiki/Memory_management https://en.wikipedia.org/wiki/Stack_register Kokoonpanokielen resurssit: Kokoonpanon ohjelmointiopas Intel® 64- ja IA-32 Architectures -ohjelmistokehittäjien oppaat | Kiitos todella hyvästä keskustelusta, mutta todellisena noobina ihmettelen, missä ohjeita pidetään? Alussa tutkijat päättivät kahden arkkitehtuurin välillä (von NEUMANN, jossa kaikkea pidetään DATA: na ja HARVARD, jossa muistialue varattiin ohjeille ja toinen tiedoille). Viime kädessä menimme von Neumannin suunnittelun kanssa, ja nyt kaikkea pidetään 'samana'. Tämä vaikeutti minua, kun opin kokoonpanoa https://www.cs.virginia.edu/~evans/cs216/guides/x86.html koska he puhuvat rekistereistä ja pinon osoittimista. Kaikki yllä mainitaan DATA. Oletan, että koska käsky on määritelty asia, jolla on erityinen muistinjalanjälki, se menisi pinoon, joten kaikki kokoonpanossa keskustellut 'nuo' rekisterit ovat pinossa. Tietysti sitten tuli olio-ohjelmointi, jossa käskyt ja tiedot tulivat dynaamiseen rakenteeseen, joten nyt myös ohjeet pidettäisiin kasaan? | Erittäin aktiivinen kysymys. Ansaitse 10 mainetta vastaamiseksi tähän kysymykseen. Maineen vaatimus auttaa suojaamaan tätä kysymystä roskapostilta ja vastaamattomuudelta. Eikö vastausta etsit? Selaa muita kysymyksiä, jotka on merkitty muistinhallintapino kieli-agnostinen kasa dynaaminen-muistin kohdentaminen tai kysy oma kysymyksesi.